/**
 * This file is part of iSecurePasswords.
 *
 * iSecurePasswords is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * iSecurePasswords is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * iSecurePasswords. If not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Matthew MacGregor Created: 2012 iSecurePasswords, copyright 2013
 * Sudolink, LLC
 *
 */
package com.sudolink.isp.app;

import com.matsuzine.utils.FileSystem;
import com.matsuzine.utils.SysInfo;
import com.sudolink.cryptodata.CryptInfoBundle;
import com.sudolink.cryptodata.SecureDataManager;
import com.sudolink.io.FileUtils;
import com.sudolink.isp.ui.GateKeeper;
import com.sudolink.isp.ui.eula.EULAViewer;
import com.sudolink.isp.util.HelperMethods;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Date;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.UIManager;
import org.apache.commons.codec.digest.DigestUtils;

/**
 *
 * @author dev
 */
public class Application {

    private static SecureDataManager secureDataManager;
    private static String pathToDatabase;
    private static CryptInfoBundle cryptInfoBundle;
    private static boolean isDebug = false;
    private static long lastUserInteractionTime = new Date().getTime();

    /**
     * @return the secureDataElementManager
     */
    public static SecureDataManager getSecureDataManager() {
        return secureDataManager;
    }

    /**
     * @param aSecureDataManager
     */
    public static void setSecureDataManager(SecureDataManager aSecureDataManager) {
        secureDataManager = aSecureDataManager;
    }

    public static String getPathToAppDataDirectory() {
        String sudolinkAppDataDir = new File(Constants.COMPANY_NAME, Constants.APP_NAME).toString();
        if (Application.isDebug()) {
            sudolinkAppDataDir += ".debug";
        }
        String dataDir = FileSystem.getAppDataDirectory();
        String appDataDirectory = new File(dataDir, sudolinkAppDataDir).getAbsolutePath();
        return appDataDirectory;
    }

    /**
     * @return the pathToDatabase
     */
    public static String getPathToDatabase() {
        return pathToDatabase;
    }

    /**
     * @param aPathToDatabase the pathToDatabase to set
     */
    public static void setPathToDatabase(String aPathToDatabase) {
        pathToDatabase = aPathToDatabase;
    }

    /**
     * @return the privateKeys
     */
    public static CryptInfoBundle getPrivateKeys() {
        return cryptInfoBundle;
    }

    /**
     * @param aPrivateKeys the privateKeys to set
     */
    public static void setPrivateKeys(CryptInfoBundle aPrivateKeys) {
        cryptInfoBundle = aPrivateKeys;
    }

    /**
     * @return the applicationVersion
     */
    public static String getApplicationVersion() {
        return Version.getVersion();
    }

    /**
     * @return the isDebug
     */
    public static boolean isDebug() {
        return isDebug;
    }

    /**
     * @param aIsDebug the isDebug to set
     */
    public static void setDebug(boolean aIsDebug) {
        isDebug = aIsDebug;
    }
    
    public static boolean isDataVerificationSignatureValid() {
        String dvs = getDataVerificationSignature();
        boolean isValid = false;
        if( dvs == null ) {
            System.out.println("No data verification signature found. Adding one now.");
            setDataVerificationSignature();
            isValid = true;
        } else {
            String md5 = calculateDataVerificationSignature();
            if( md5 == null ) {
                return false;
            } else {
                if( md5.equals(dvs) ) {
                    isValid = true;
                }
            }
        }
        return isValid;
    }

    public static String calculateDataVerificationSignature() {
        String md5 = DigestUtils.md5Hex("");
        try {
            return FileUtils.md5File(new File(Application.getPathToDatabase()));
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }
        return md5;
    }
    
    public static String getDataVerificationSignature() {
        Properties pm;
        try {
            pm = PropertiesManager.getInstance();
            return pm.getProperty(PropertiesManager.DATA_INTEGRITY_SIGNATURE, null);
        } catch (IOException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
    
    public static void setDataVerificationSignature( ) {
        Properties pm;
        try {
            pm = PropertiesManager.getInstance();
            String md5 = calculateDataVerificationSignature();
            md5 = ( md5 != null ) ? md5 : DigestUtils.md5Hex("");
            pm.setProperty(PropertiesManager.DATA_INTEGRITY_SIGNATURE, md5);
            PropertiesManager.commit();
        } catch (IOException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    /**
     * @return the unlockCode
     */
    public static String getUnlockCodeMD5() {

        Properties pm;
        try {
            pm = PropertiesManager.getInstance();
            return pm.getProperty(PropertiesManager.UNLOCK_CODE_MD5);
        } catch (IOException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;

    }

    /**
     * @param aUnlockCode the unlockCode to set
     */
    public static void setUnlockCode(String aUnlockCode) {

        Properties pm;
        try {
            pm = PropertiesManager.getInstance();
            pm.setProperty(PropertiesManager.UNLOCK_CODE_MD5, DigestUtils.md5Hex(aUnlockCode));
            PropertiesManager.commit();
        } catch (IOException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    /**
     * @return the lastAccessedTime
     */
    public synchronized static long getLastUserInteractionTime() {
        return lastUserInteractionTime;
    }

    public synchronized static void refreshLastUserInteractionTime() {
        lastUserInteractionTime = new Date().getTime();
    }

    /**
     * This method returns a persisted value if available, or a default if not.
     *
     * @return
     */
    public synchronized static long getLockTimeoutInMilliseconds() {
        long msInt = 300000;
 
        try {
            Properties pm = PropertiesManager.getInstance();
            String ms = pm.getProperty(PropertiesManager.MILLISECONDS_UNTIL_LOCKED, "300000");
            msInt = Long.parseLong(ms);
        } catch (IOException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }

 
        return msInt;
    }
    
    /**
     * 
     * @return Number of seconds until the application should lock.
     */
    public synchronized static long getLockTimeoutInSeconds() {
        return HelperMethods.millisecondsToSeconds(getLockTimeoutInMilliseconds());
    }

    /**
     * This method sets a persistent value.
     *
     * @param ms
     */
    public static void setMillisecondsUntilLocked(int ms) {
        Properties pm;
        try {
            pm = PropertiesManager.getInstance();
            pm.setProperty(PropertiesManager.MILLISECONDS_UNTIL_LOCKED, ms + "");
            PropertiesManager.commit();
        } catch (IOException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public static boolean isEULASigned() {
        Properties pm;
        try {
            pm = PropertiesManager.getInstance();
            String result = pm.getProperty(PropertiesManager.EULA_SIGNED, "false");
            if (result != null ) {
                return Boolean.parseBoolean(result);
            } 
        } catch (IOException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return false;
    }
    
    public static void setEULASigned( boolean isSigned ) {
        Properties pm;
        try {
            pm = PropertiesManager.getInstance();
            pm.setProperty(PropertiesManager.EULA_SIGNED, "true");
            PropertiesManager.commit();
        } catch (IOException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static int getNumberBackupsRetained() {
        try {
            return Integer.parseInt(
                        PropertiesManager.getInstance().getProperty(
                        PropertiesManager.NUMBER_BACKUP_FILES_RETAINED, "7"));
        } catch (IOException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }
        return 7;
    }
    
    public static void setNumberBackupsRetained(int num) {
             
        Properties pm;
        try {
            pm = PropertiesManager.getInstance();
            pm.setProperty(PropertiesManager.NUMBER_BACKUP_FILES_RETAINED, "7");
            PropertiesManager.commit();
        } catch (IOException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }
        
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {

        if (args.length > 0 && args[0].equals("debug")) {
            Application.setDebug(true);
        }

        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /*
         * If Nimbus (introduced in Java SE 6) is not available, stay with the
         * default look and feel. For details see
         * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            
            if( SysInfo.getPlatform() == SysInfo.Platform.MAC_OS ) {
                System.setProperty("apple.laf.useScreenMenuBar", "true");
                System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Test");
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } else {
                javax.swing.UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            }      

        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(GateKeeper.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>
        
        /*
         * Create and display the form
         */
        java.awt.EventQueue.invokeLater(() -> {
            EULAViewer viewer = new EULAViewer("license", (String[] args1) -> {
                GateKeeper gk = new GateKeeper();
                gk.setLocationRelativeTo(null);
                gk.setVisible(true);
            });
            viewer.promptEULA();
        });
    }
}
